classdef GaltonCorrection 
    %This is an class for the Galton strategies
    properties
       galton_coeffs;
       galton_nstocks;
       pre_window; %The estimation window
       post_window; %The period of the subsequent realized window
    end
    
    methods
        function [obj] = getGaltonCoefficients(obj, Y , T , ids)
                
                if ~exist('ids','var')
                    ids = true(size(Y));
                end

                galton.reg.nomodel.monthly.FF=NaN(T,2,4,3);

                nstocks=NaN(T,1);
                %Explain why loop starts with +2. Helps align with other
                %matrices
                for t=obj.pre_window+2:T-obj.post_window

                    %------------------------------------------------------------------
                    %Select only those assets with roll months of previous returns and full
                    %history of returns in the subsequent 'subs' months and estimate the
                    %residuals and the betas:

                    has_returns=(sum(isnan(Y(ids(:,t),t-obj.pre_window+1:t+obj.post_window)),2)==0);
                    
                    nstocks(t,1)=sum(has_returns);



                    %returns in the past and in the future
                    yfut=Y(ids(:,t),t+1:t+obj.post_window); 
                    ypast=Y(ids(:,t),t-obj.pre_window+1:t);

                    %------------------------------------------------------------------
                    % The covariances and correlations for all pairs (both in the past and
                    % in the future) and the variances and average returns for all stocks.

                    X=ypast(has_returns,:);
                    pairs_past_corr=corr(X');
                    pairs_past_cov=cov(X');
                    
                    Areturn_past=mean(X,2);

                    var_past=diag(pairs_past_cov);

                    covspast=triu(pairs_past_cov,1);
                        covspast=covspast(covspast~=0);

                        corrspast=triu(pairs_past_corr,1);
                        corrspast=corrspast(corrspast~=0);



                    X=yfut(has_returns,:);
                    pairs_future_corr=corr(X');pairs_future_cov=cov(X');
                    
                    Areturn_fut=mean(X,2);

                        var_fut=diag(pairs_future_cov);

                        covsfut=triu(pairs_future_cov,1);
                        covsfut=covsfut(covsfut~=0);

                        corrsfut=triu(pairs_future_corr,1);
                        corrsfut=corrsfut(corrsfut~=0);



                     %------------------------------------------------------------------
                     %Storing the information in the structure "Galton" 

                     %------------------------------------------------------------------
                     % The regression of the future realized values on the past. 

                     whichstats={'beta','tstat','rsquare'};
                     a=regstats(covsfut,covspast,'linear',whichstats);

                     galton.reg.nomodel.monthly.FF(t,:,1,1)=a.beta;
                     galton.reg.nomodel.monthly.FF(t,:,1,2)=a.tstat.t;
                     galton.reg.nomodel.monthly.FF(t,:,1,3)=a.rsquare;

                     a=regstats(corrsfut,corrspast,'linear',whichstats);

                     galton.reg.nomodel.monthly.FF(t,:,2,1)=a.beta;
                     galton.reg.nomodel.monthly.FF(t,:,2,2)=a.tstat.t;
                     galton.reg.nomodel.monthly.FF(t,:,2,3)=a.rsquare;

                     a=regstats(var_fut,var_past,'linear',whichstats);

                     galton.reg.nomodel.monthly.FF(t,:,3,1)=a.beta;
                     galton.reg.nomodel.monthly.FF(t,:,3,2)=a.tstat.t;
                     galton.reg.nomodel.monthly.FF(t,:,3,3)=a.rsquare;


                     a=regstats(Areturn_fut,Areturn_past,'linear',whichstats);

                     galton.reg.nomodel.monthly.FF(t,:,4,1)=a.beta;
                     galton.reg.nomodel.monthly.FF(t,:,4,2)=a.tstat.t;
                     galton.reg.nomodel.monthly.FF(t,:,4,3)=a.rsquare;

                end

                %data.corr.nstocks=nstocks;
                galton.reg.nomodel.monthly.nstocks=nstocks;
                %data.galton=galton;

                %-----------------------------------------------------------------------
                %This concludes getting the galton structure
                %-----------------------------------------------------------------------

                obj.galton_coeffs = galton.reg.nomodel.monthly.FF;
                obj.galton_nstocks = galton.reg.nomodel.monthly.nstocks;

            end


    function [  ] = output_galton(obj)
        
        nstocks = obj.galton_nstocks;
        galton = obj.galton_coeffs;

        nstocks=nstocks(isnan(nstocks)==0); 

        for n=1:4

            slopes=galton(:,2,n,1);
            slopes=slopes(isnan(slopes)==0);
            
            tstats_zero=galton(:,2,n,2);
            tstats_zero=tstats_zero(isnan(tstats_zero)==0);
            tstats_one=(slopes-1)./(slopes./tstats_zero);
            
            rsquares=galton(:,2,n,3);
            rsquares=rsquares(isnan(rsquares)==0);
            

            intercepts=galton(:,1,n,1);
            intercepts=intercepts(isnan(intercepts)==0);
            
            if n<=2
                num=(nstocks.*(nstocks-1))/2;  
            else
                num=nstocks;
            end

            num=num(isnan(num)==0);

            tab_reg(n,1)=mean(intercepts);
            tab_reg(n,2)=t_nw_const(intercepts,12);
            tab_reg(n,3)=mean(slopes);
            tab_reg(n,4)=t_nw_const(slopes,12);

            tab_reg(n,5)=sum(tstats_zero(isnan(tstats_zero)==0)>tinv(.95,num(1)))/...
                length(tstats_zero(isnan(tstats_zero)==0));

            tab_reg(n,6)=t_nw_const(slopes-1,12);
            tab_reg(n,7)=nansum(tstats_one(isnan(tstats_one)==0)<tinv(.05,num(1)))/length(tstats_one(isnan(tstats_one)==0));
            tab_reg(n,8)=nanmean(rsquares)*100;
            tab_reg(n,9)=min(num);
            tab_reg(n,10)=mean(num);
            tab_reg(n,11)=max(num);
        end
        tab_reg = tab_reg(1:4,:)';

        label = { 
        'Intercept';
        't-stat (=0)'; 
        'Slope ';
        't-stat(=0)'; 
        'Greater than 0 (\%)';
        't-stat(=1)';
        'Smaller than 1 (\%)'; 
        'R-square (\%)';
        'Min ';
        'Average';
        'Max ';};
        
        latexOutput(tab_reg,zeros(1,size(tab_reg,1)),label,'Table 7: Galton Coefficients');

    end
        
        

  

    end
    
end

